TokenDeclarator = (
    name : Identifier?,
    value : StringLiteral?,
    text : StringLiteral?
)

TokenDeclarationKind: one of
    Token
    EndMarker LayoutMarker HiddenToken
    Keyword ReservedWord ContextualWord

TokenDeclaration = (
    kind : TokenDeclarationKind,
    items : [TokenDeclarator]+,
    assignedType : TypeExpression?
)

TokenReference:
    Named (name : Identifier)
    Literal (value : StringLiteral)

OperatorDeclarationKind: one of
    Left Right Nonassociative
    Shift Reduce

OperatorDeclaration = (
    kind : OperatorDeclarationKind,
    items : [TokenReference]+
)

StartDeclaration = (
    isExclusive : bool,
    items : [Identifier]+
)

GoalDeclarator = (
    name : Identifier,
    endMarkers : [TokenReference]
)

GoalDeclaration = (items : [GoalDeclarator]+)

LexicalPrecedenceOperator: one of
    LessTilde LessMinus MinusTilde
    LessLess LessS
    MinusLess MinusS

LexicalPrecedenceDeclarator = (
    left : TokenReference,
    op : LexicalPrecedenceOperator,
    right : TokenReference
)

LexicalPrecedenceDeclaration = (items : [LexicalPrecedenceDeclarator]+)

ExceptionDescriptor = (
    name : Identifier,
    baseName : Identifier?
)

ExceptionDeclaration = (
    items : [Identifier]+,
    baseName : Identifier?
)

DefineDeclaration = (
    name : [Identifier]+,
    value : Expression
)

IncludeDeclarator:
    Named (name : [Identifier]+)
    Literal (value : StringLiteral)

IncludeDeclaration = (items : [IncludeDeclarator]+)

Directive:
    Token (declaration : TokenDeclaration)
    Operator (declaration : OperatorDeclaration)
    Start (declaration : StartDeclaration)
    Goal (declaration : GoalDeclaration)
    LexicalPrecedence (declaration : LexicalPrecedenceDeclaration)
    Exception (declaration : ExceptionDeclaration)
    Define (declaration : DefineDeclaration)
    Include (declaration : IncludeDeclaration)

DirectiveDeclaration = (items : [Directive])

%%

TokenDeclarator as TokenDeclarator:
    QuoteStringLiteral => TokenDeclarator.New(None, $1, None, @@)
    Name => TokenDeclarator.New($1, None, None, @@)
    Name '(' QuoteStringLiteral ')' => TokenDeclarator.New($1, $3, None, @@)
    Name '(' StringLiteral ')' => TokenDeclarator.New($1, None, $3, @@)

TokenDeclarators as [TokenDeclarator]:
    TokenDeclarator => Sequence.Create($1)
    TokenDeclarators ',' TokenDeclarator => Sequence.Append($1, $3)

TokenDeclarationKind as TokenDeclarationKind:
    '%token' => TokenDeclarationKind.Token
    '%endmarker' => TokenDeclarationKind.EndMarker
    '%layout' => TokenDeclarationKind.LayoutMarker
    '%hidden' => TokenDeclarationKind.HiddenToken
    '%keyword' => TokenDeclarationKind.Keyword
    '%reserved' => TokenDeclarationKind.ReservedWord
    '%contextual' => TokenDeclarationKind.ContextualWord

TokenDeclaration as TokenDeclaration:
    TokenDeclarationKind TokenDeclarators OptionalTypeExpression => TokenDeclaration.New($1, $2, $3, @@)

OptionalTypeExpression as TypeExpression?:
    => None
    ':' TypeExpression => $2

TokenReference as TokenReference:
    Name => TokenReference.NewNamed($1, @@)
    QuoteStringLiteral => TokenReference.NewLiteral($1, @@)

TokenReferences as [TokenReference]:
    TokenReference => Sequence.Create($1)
    TokenReferences ',' TokenReference => Sequence.Append($1, $3)

OperatorDeclarationKind as OperatorDeclarationKind:
    '%left' => OperatorDeclarationKind.Left
    '%right' => OperatorDeclarationKind.Right
    '%nonassoc' => OperatorDeclarationKind.Nonassociative
    '%shift' => OperatorDeclarationKind.Shift
    '%reduce' => OperatorDeclarationKind.Reduce

OperatorDeclaration as OperatorDeclaration:
    OperatorDeclarationKind TokenReferences => OperatorDeclaration.New($1, $2, @@)

StartDeclarator as Identifier:
    Name => $1

StartDeclarators as [Identifier]:
    StartDeclarator => Sequence.Create($1)
    StartDeclarators ',' StartDeclarator => Sequence.Append($1, $3)

StartDeclarationKind as bool:
    '%start' => False
    '%xstart' => True

StartDeclaration as StartDeclaration:
    StartDeclarationKind StartDeclarators => StartDeclaration.New($1, $2, @@)

EndMarkerList as [TokenReference]:
    => default([TokenReference])
    '%' TokenReference => Sequence.Create($2)
    '%' '{' TokenReferences '}' => $3

GoalDeclarator as GoalDeclarator:
    Name EndMarkerList => GoalDeclarator.New($1, $2, @@)

GoalDeclarators as [GoalDeclarator]:
    GoalDeclarator => Sequence.Create($1)
    GoalDeclarators ',' GoalDeclarator => Sequence.Append($1, $3)

GoalDeclaration as GoalDeclaration:
    '%goal' GoalDeclarators => GoalDeclaration.New($2, @@)

LexicalPrecedenceOperator as LexicalPrecedenceOperator:
    '<~' => LexicalPrecedenceOperator.LessTilde
    '<-' => LexicalPrecedenceOperator.LessMinus
    '-~' => LexicalPrecedenceOperator.MinusTilde
    '<<' => LexicalPrecedenceOperator.LessLess
    '<s' => LexicalPrecedenceOperator.LessS
    '-<' => LexicalPrecedenceOperator.MinusLess
    '-s' => LexicalPrecedenceOperator.MinusS

LexicalPrecedenceDeclarator as LexicalPrecedenceDeclarator:
    TokenReference LexicalPrecedenceOperator TokenReference => LexicalPrecedenceDeclarator.New($1, $2, $3, @@)

LexicalPrecedenceDeclarators as [LexicalPrecedenceDeclarator]:
    LexicalPrecedenceDeclarator => Sequence.Create($1)
    LexicalPrecedenceDeclarators ',' LexicalPrecedenceDeclarator => Sequence.Append($1, $3)

LexicalPrecedenceDeclaration as LexicalPrecedenceDeclaration:
    '%lexprec' LexicalPrecedenceDeclarators => LexicalPrecedenceDeclaration.New($2, @@)

ExceptionDeclaration as ExceptionDeclaration:
    '%exception' Name %+ ',' => ExceptionDeclaration.New($2, None, @@)
    '%exception' Name %+ ',' ':' Identifier => ExceptionDeclaration.New($2, $4, @@)

DefineDeclaration as DefineDeclaration:
    '%define' Name %+ '.' BitwiseXorExpression => DefineDeclaration.New($2, $3, @@)

IncludeDeclarator as IncludeDeclarator:
    Name %+ '.' => IncludeDeclarator.NewNamed($1, @@)
    StringLiteral => IncludeDeclarator.NewLiteral($1, @@)

IncludeDeclarators as [IncludeDeclarator]:
    IncludeDeclarator => Sequence.Create($1)
    IncludeDeclarators ',' IncludeDeclarator => Sequence.Append($1, $3)

IncludeDeclaration as IncludeDeclaration:
    '%include' IncludeDeclarators => IncludeDeclaration.New($2, @@)

Directive as Directive:
    TokenDeclaration => Directive.NewToken($1, @@)
    OperatorDeclaration => Directive.NewOperator($1, @@)
    StartDeclaration => Directive.NewStart($1, @@)
    GoalDeclaration => Directive.NewGoal($1, @@)
    LexicalPrecedenceDeclaration => Directive.NewLexicalPrecedence($1, @@)
    ExceptionDeclaration => Directive.NewException($1, @@)
    DefineDeclaration => Directive.NewDefine($1, @@)
    IncludeDeclaration => Directive.NewInclude($1, @@)

Directives as [Directive]:
    Directive NewLine => Sequence.Create($1)
    Directives Directive NewLine => Sequence.Append($1, $2)

DirectiveList as [Directive]:
    => default([Directive])
    Directives => $1

DirectiveDeclaration as DirectiveDeclaration:
    DirectiveList => DirectiveDeclaration.New($1, @@)
